#pragma once
#include<unordered_map>
#include<QMutex>
#include"ResourceManage.h"
using namespace std;

enum CACHETYPE{LRU};


class PageCache{
private:
    //不用读写锁的原因：大概率在缓存淘汰的时候数据也会进行改变
    QMutex mutex;
public:
    virtual void clear() = 0;
    virtual ResourceManage* get(const string& key) = 0;
    virtual void put(const string& key, ResourceManage* value) = 0;
    virtual void lock(){mutex.lock();}  //往往多个操作一起使用，因此需要在调用层上锁来保证原子性。
    virtual void unLock(){mutex.unlock();}
};




class valueItem
{
public:
    string key;
    ResourceManage* value;
    valueItem* last;
    valueItem* next;
    valueItem(const string& key, ResourceManage* value) : key(key), value(value), last(nullptr), next(nullptr){}
    //析构函数里面都是同步释放 仅在最头部控制异步
    ~valueItem(){
        last = nullptr;
        next = nullptr;
        ResourceMemManager::asyncClearResMem(value);        //资源异步释放
    }
};


class LRUCache :public PageCache
{
    using node = valueItem;

private:
    unordered_map<string, node*> allNode;
    node* head = nullptr;
    node* tail = nullptr;
    unsigned int size;

    void removeHead()
    {
        allNode.erase(head->key);
        node* oldHead = head;
        head = head->next;
        head->last = nullptr;
        MemUtil::clearPtrMem(oldHead); //节点是同步释放 里面的资源异步释放
        //释放可以异步的原因是： 在操作之后别的线程获取要释放的资源，因为移除操作是同步的所以不会获取到正在释放的资源
    }

public:
    LRUCache(const unsigned int& size) : size(size) {}

    virtual ~LRUCache(){
        clear();
    }

    virtual void clear(){
        head = nullptr;
        tail = nullptr;
        for(auto& it : allNode){
            MemUtil::clearPtrMem(it.second);
        }
        allNode.clear();
    }

    virtual ResourceManage* get(const string& key)
    {
        const auto& iter = allNode.find(key);
        if (iter == allNode.end())
            throw string("cannot find");
        node* target = iter->second;
        node* next = target->next;
        node* last = target->last;
        //把节点从目前位置取出
        if (next != nullptr)
        {
            next->last = last;
        }
        else
        {
            return target->value; //现在已经是最后一个了，直接返回
        }
        if (last != nullptr)
        {
            last->next = next;
        }
        else
        {
            head = target->next; //现在已经是第一个了，拿走
            head->last = nullptr;
        }
        //把节点放到最后
        tail->next = target; //现在tail变成倒数第二个
        target->last = tail;
        target->next = nullptr;
        tail = target;
        return target->value;
    }

    virtual void put(const string& key, ResourceManage* value)
    {
        const auto& iter = allNode.find(key);
        if (iter == allNode.end())
        {
            node* target = new node(key, value);
            allNode[key] = target;
            if (head == nullptr && tail == nullptr) //其实他俩不会只有一个为nullptr
            {
                head = target;
                tail = target;
            }
            else
            {
                //原先的tail变倒数第二个
                tail->next = target;
                target->last = tail;
                tail = target;
                if (allNode.size() > this->size)
                    removeHead();
            }
        }
        else{
            throw string ("no assignment again");
        }
    }
};



class CacheUtil{
public:
    static PageCache* getPageCache(const CACHETYPE& cacheType, const int& size){
        if(cacheType == LRU){
            return new LRUCache(size);
        }
        throw string ("cache type error");
    }
};

